import { Scene, PerspectiveCamera, WebGLRenderer, CanvasTexture, HemisphereLight, MeshStandardMaterial, Mesh, DirectionalLight, Vector3, PlaneGeometry } from 'three';
import { fetchImage } from './utils';
import { OrbitControls } from 'three/examples/jsm/Addons.js';

function getColorNumber(color: string) {
  return {
    r: Number('0x' + color.slice(1, 3)),
    g: Number('0x' + color.slice(3, 5)),
    b: Number('0x' + color.slice(5, 7))
  };
}

/**
 *
 * @param value 0 - 255
 * @param maxColor
 * @param minColor
 */
function getColor(value: number, maxColor: string, minColor: string) {
  const min = getColorNumber(minColor);
  const max = getColorNumber(maxColor);
  const r = max.r - min.r;
  const g = max.g - min.g;
  const b = max.b - min.b;
  const v = value / 255;
  return {
    r: r * v + min.r,
    g: g * v + min.g,
    b: b * v + min.b
  };
}

import React, { useEffect, useRef } from 'react';

export default () => {
  const mapRef = useRef<HTMLDivElement>(null);
  const canvasRef = useRef<HTMLCanvasElement>(null);
  const scene = new Scene();
  const camera = new PerspectiveCamera(75, 1, 0.1, 5000);
  const renderer = new WebGLRenderer({ antialias: true, alpha: true });
  const material = new MeshStandardMaterial({ wireframe: false, color: 0xffffff });
  const controls = new OrbitControls(camera, renderer.domElement);
  let timer: number;
  let ctx: CanvasRenderingContext2D;
  useEffect(() => {
    ctx = canvasRef.current?.getContext('2d') as CanvasRenderingContext2D;
    drawImage();
    drawMap();
    animate();
    return () => cancelAnimationFrame(timer);
  }, []);
  const drawImage = () => {
    fetchImage('ASTGTMV003_N00E116.1.jpg').then((res) => {
      const imageSize = 1024;
      canvasRef.current!.width = canvasRef.current!.height = imageSize;
      ctx.drawImage(res, 0, 0, imageSize, imageSize);
      const data = ctx.getImageData(0, 0, imageSize, imageSize) as ImageData;
      const geometry = new PlaneGeometry(2000, 2000, imageSize - 1, imageSize - 1);

      let r: Array<number> = [];
      for (let i = 0; i < data.data.length; i = i + 4) r.push(data.data[i]);
      // 0
      const minColor = '#0000ff';
      // 255
      const maxColor = '#00ff00';
      for (let i = 0; i < data.data.length; i = i + 4) {
        const color = getColor(data.data[i], maxColor, minColor);
        data.data[i] = color.r;
        data.data[i + 1] = color.g;
        data.data[i + 2] = color.b;
      }
      ctx.putImageData(data, 0, 0);
      const vertices = geometry.attributes.position.array;
      for (let i = 0; i < r.length; i++) vertices[i * 3 + 2] = r[i] / 5;

      material.map = new CanvasTexture(canvasRef.current!);
      material.needsUpdate = true;
      const mesh = new Mesh(geometry, material);
      mesh.rotateX(-Math.PI / 2);
      scene.add(mesh);
      geometry.computeVertexNormals();
    });
  };
  const drawMap = () => {
    const width = mapRef.current!.clientWidth;
    const height = mapRef.current!.clientHeight;
    camera.aspect = width / height;
    camera.updateProjectionMatrix();
    renderer.setSize(width, height);
    mapRef.current!.appendChild(renderer.domElement);

    const light = new DirectionalLight(0xffffff, 1);
    light.position.set(5, 4, 3);
    scene.add(light);
    const light2 = new HemisphereLight(0xffffbb, 0x080820, 1);
    scene.add(light2);

    camera.position.set(0, 600, 800);
    camera.lookAt(new Vector3(0, 0, 0));
    controls.minDistance = 10;
    controls.maxDistance = 1000;
    controls.maxPolarAngle = Math.PI / 2;
  };
  const animate = () => {
    timer = requestAnimationFrame(animate);
    renderer.render(scene, camera);
  };
  return (
    <div style={{ height: '100%', width: '100%', position: 'relative' }}>
      <div ref={mapRef} style={{ height: '100%', width: '100%' }}></div>
      <canvas ref={canvasRef} style={{ height: '300px', width: '300px', position: 'absolute', top: '0', left: 0 }}></canvas>
    </div>
  );
};
